/* systick_utils.c
 * Implementation of SysTick utilities.
 */
#include "config.h" /* for CPUCLK_FREQ and msTicks */
#include "..\vendor\ti\driverlib\dl_common.h" /* for DL_Common_delayCycles */

#ifdef DEBUG
#include <assert.h>
#endif

void set_systick_ms(uint32_t ms)
{
    uint64_t ticks = ((uint64_t)CPUCLK_FREQ * (uint64_t)ms) / 1000ULL;

    if (ticks < 2ULL) {
        ticks = 2ULL;
    } else if (ticks > 0x01000000ULL) {
        ticks = 0x01000000ULL;
    }

#ifdef DEBUG
    /* SysTick_Config returns 0 on success (CMSIS). Assert when debugging. */
    uint32_t rc = DL_SYSTICK_config((uint32_t)ticks); 
    assert(rc == 0);
#else
    DL_SYSTICK_config((uint32_t)ticks);
#endif
}

void delay_ms(uint32_t ms)
{
    extern volatile uint32_t msTicks; /* declared in config.h and defined in bsp/config.c */
    uint32_t start = msTicks;
    while ((uint32_t)(msTicks - start) < ms) {
        /* busy wait */
    }
}

void delay_ticks(uint32_t ticks)
{
    extern volatile uint32_t msTicks; /* declared in config.h and defined in bsp/config.c */
    uint32_t start = msTicks;
    while ((uint32_t)(msTicks - start) < ticks) {
        /* busy wait */
    }
}

void delay_us(uint32_t us)
{
    /* Calculate required cycles for requested microseconds.
     * cycles = CPUCLK_FREQ (Hz) * us / 1_000_000
     * Use 64-bit intermediate to avoid overflow.
     */
    uint64_t cycles = ((uint64_t)CPUCLK_FREQ * (uint64_t)us) / 1000000ULL;

    if (cycles == 0ULL) {
        /* ensure at least one cycle to avoid calling with 0 */
        cycles = 1ULL;
    }

    /* DL_Common_delayCycles takes uint32_t; clamp if too large */
    while (cycles > 0xFFFFFFFFULL) {
        DL_Common_delayCycles(0xFFFFFFFFU);
        cycles -= 0xFFFFFFFFULL;
    }

    DL_Common_delayCycles((uint32_t)cycles);
}
